package com.std.getstuffdone;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;

import models.DataSource;
import models.DbHelper;
import models.PlanningList;
import models.Schedule;
import models.ScheduleMaker;
import models.Task;
import models.Utility;

import com.std.getstuffdone.R;

import android.app.AlertDialog;
import android.app.ListActivity;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.text.format.Time;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.*;

/**
 * This class handles the Planning Screen UI and controls
 * @author Team STD
 *
 */
public class PlanningScreenActivity extends ListActivity implements OnClickListener {
        
        // constant string values
        private static final String TAG = "PLANNING_SCREEN_ACTIVITY";
		private static final String NEW_TASK_CONFLICT = "NEW TASK CONFLICT";
		private static final String EDIT_TASK_CONFLICT = "EDIT TASK CONFLICT";
        private final String STARTTIMELABEL = "Start Time: ";
        private final String DURATIONLABEL = "Duration: ";
        private final String TRAVELTIMELABEL = "Travel Time: ";
        private final String PRIORITYLABEL = "Priority: ";
        
        // a request code for starting new Activities
        int requestCode = 0;
         
        // row position of task that is selected by a long touch
        private long selectedRowPosition;
        
        // declared variables to be used as needed
        private PlanningList planningList;
        private List<Task> tasksToDisplay;
        private List<Task> regenerateTasks;
        private DataSource dataSource;
        static  ArrayList<HashMap<String,String>> list;
        private Collection<Task> scheduleList;
            
        // this method is called every time the planning screen is displayed
        public void onCreate(Bundle savedInstanceState){
                super.onCreate(savedInstanceState);
                setContentView(R.layout.planningscreenactivity);
        
                // a singleton database utility that handles database methods
                dataSource = DataSource.getInstance(getApplicationContext());
                
                // get all tasks in the planning screen.
                displayPlanningTasks();
                                                
                // set the android list view
                ListView lv = getListView();
                lv.setTextFilterEnabled(true);
                registerForContextMenu(lv);
                
                // get handlers and set listeners to buttons
                Button addTaskButton = (Button)findViewById(R.id.addTaskButton);
                Button generateButton = (Button)findViewById(R.id.generateScheduleButton);
                addTaskButton.setOnClickListener(this);
                generateButton.setOnClickListener(this);
        }
        
        // This method gets the information of all tasks from the PLANNINGLIST table of the database abd
        // and displays it on the Planning Screen
        private void displayPlanningTasks() {
                
                // clear old tasks from planning list 
                planningList = new PlanningList();
                
                // get tasks from database
                dataSource.open();
                List<Task> tasks = dataSource.getAllTasks(DbHelper.TABLE_PLANNINGTASKS);
                dataSource.close();
                        
                // populate planningList with all tasks from database
                tasksToDisplay = new ArrayList<Task>();
                regenerateTasks = new ArrayList<Task>();
                for(Task t : tasks) {
                    planningList.addTask(t);
                    Task copiedTask = new Task(t.getID(), t.getTitle(),t.getStartTime(), t.getEstimatedDuration(), t.getEstimatedTravel(), t.getPriority(), false);
                    Task copiedTask2 = new Task(t.getID(), t.getTitle(),t.getStartTime(), t.getEstimatedDuration(), t.getEstimatedTravel(), t.getPriority(), false);
                    tasksToDisplay.add(copiedTask);
                    regenerateTasks.add(copiedTask2);
                }
                
                // set the adapter information to display data
                list = new ArrayList<HashMap<String,String>>();
                SimpleAdapter adapter = new SimpleAdapter(this,list,R.layout.planning_list_item,
                                new String[] {"taskId","title","startTime","duration","travelTime","priority"},
                                new int[] {R.id.taskId,R.id.title,R.id.startTime, R.id.duration, R.id.travelTime, R.id.priority}
                );
                                
                populateList(tasksToDisplay);
                setListAdapter(adapter);
        }

        // populates list with data to display from a list of tasks
        // @param tasks A list of tasks to be displayed on screen
        private void populateList(List<Task> tasks) {
                for(Task t : tasks) {
                        HashMap<String,String> temp = new HashMap<String,String>();
                        temp.put("taskId", String.valueOf(t.getID()));
                        temp.put("title", t.getTitle());
                        temp.put("startTime", STARTTIMELABEL + parseTime(t.getStartTime()));
                        temp.put("duration", DURATIONLABEL + t.getEstimatedDuration() + " min");
                        temp.put("travelTime", TRAVELTIMELABEL + t.getEstimatedTravel() + " min");
                        temp.put("priority", PRIORITYLABEL + Utility.getPriorityString(t.getPriority()));
                        list.add(temp);
                }
        }
        
        // parses Time object to display in HH:MM string format
        // @param time Time object to display
        // @return String with time in HH:MM format. 'Time not set' if time is null
        private String parseTime(Time time) {
                if (time == null) {
                        return "Not Set";
                }
                return time.toString().substring(9, 11) + ":" + time.toString().substring(11,13);
        }
         
        // This method handles the button clicks to start new activities
        public void onClick(View v) {
                int viewId = v.getId();
                if(viewId == R.id.addTaskButton){
                        // launch activity to get new task info
                        launchEnterTaskInfoActivity();
                        
                } else {
                        //launch activity to set schedule start and end times
                        launchStartEndTimeEntryActivity();
                }
        }
        
        // This method launches EnterTaskInfo activity to get information about a new task
        private void launchEnterTaskInfoActivity() {
                
                // bundle to indicate that activity is being called to get new task information
                Bundle bundle = new Bundle();
                bundle.putBoolean(Utility.BUNDLE_NEW_TASK_FLAG, true);
                                
                Intent newIntent = new Intent(PlanningScreenActivity.this, EnterTaskInfo.class);
                newIntent.putExtras(bundle);
                startActivityForResult(newIntent, requestCode);
                
        }
    
        // launches the activity that allows user to input schedule start/end time
        private void launchStartEndTimeEntryActivity() {
        	Intent newIntent = new Intent(this, StartEndTimeEntry.class);
        	startActivityForResult(newIntent, requestCode);
        }
        
        // displays a menu when menu button is pressed.
        @Override
         public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
              super.onCreateContextMenu(menu, v, menuInfo);
             
              MenuInflater inflater = getMenuInflater();
              inflater.inflate(R.menu.task_action_menu, menu);
         }
        
        // display a menu when an item in the planning screen is selected
        @Override
        public boolean onContextItemSelected(MenuItem item) {
                
                  // get position of view that spawned the menu and save it globally for later use
              selectedRowPosition = getTaskPosition(item);
                                
              if(item.getItemId()== R.id.edit_task){
                  // Task Editing
                  
                  // get the task info and put it in a bundle and call EnterTaskInfo
                  Bundle bundle = getTaskInformationBundle(selectedRowPosition);
                  Intent newIntent = new Intent(PlanningScreenActivity.this, EnterTaskInfo.class);
                          newIntent.putExtras(bundle);
                          startActivityForResult(newIntent, requestCode);
              }
              else if (item.getItemId() == R.id.delete_task) {
                  //Task Deletion
                  
            	  // display confirmation dialog 
            	  displayAlertDialog();
                  displayPlanningTasks();
              }
              return true;
         } 
        
        /**
         * This method gets information of the task displayed at the given row position in the list view.
         * @param selectedRowPosition is the position at which the Task info is displayed in the list view
         * @return Bundle containing information of task displayed at the given row position
         */
        private Bundle getTaskInformationBundle(long selectedRowPosition) {
                long taskId = rowPositionToTaskId(selectedRowPosition);
                Task taskToEdit = planningList.getTask(taskId);
                Time startTime = taskToEdit.getStartTime();
                String startTimeString;
                if(startTime == null){
                        startTimeString = "Set Start Time";
                } else {
                        startTimeString = taskToEdit.getStartTime().toString().substring(9, 11) + ":" +
                                                                taskToEdit.getStartTime().toString().substring(11, 13);
                }       
                Bundle bundle = new Bundle();
                bundle.putBoolean(Utility.BUNDLE_NEW_TASK_FLAG, false);
                bundle.putLong(Utility.BUNDLE_TASK_ID, taskToEdit.getID());
                bundle.putString(Utility.BUNDLE_TASK_TITLE, taskToEdit.getTitle());
                bundle.putString(Utility.BUNDLE_TASK_START_TIME, startTimeString);
                bundle.putString(Utility.BUNDLE_TASK_DURATION, String.valueOf(taskToEdit.getEstimatedDuration()));
                bundle.putString(Utility.BUNDLE_TASK_TRAVEL_TIME, String.valueOf(taskToEdit.getEstimatedTravel()));
                bundle.putInt(Utility.BUNDLE_TASK_PRIORITY, taskToEdit.getPriority());
          
            return bundle;
        }

        // This method return the id of the task, whose information is displayed in given row
        private long rowPositionToTaskId(long rowPosition) {
            HashMap<String, String> taskInfo = list.get((int) rowPosition);
            String taskIdString = taskInfo.get("taskId");
            long taskId = Long.parseLong(taskIdString);
            return taskId;
        }

        // returns the position of the view which spawned the menu
        private long getTaskPosition(MenuItem item) {
                 AdapterContextMenuInfo info;
              try {
                    info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
                } catch (ClassCastException e) {
                    Log.e(TAG, "bad menuInfo", e);
                    throw new ClassCastException();
               }
                long id = getListAdapter().getItemId(info.position);
                return id;
        }
         
         // Deletes a planning task with a given task id
         private void deletePlanningTask(long taskId) {
                dataSource.open();
                dataSource.deletePlanningTask(taskId);
                dataSource.close();
        }

         // displays a menu when a menu button is pressed
         @Override
         public boolean onOptionsItemSelected(MenuItem item) {
                 // Handle item selection
                 switch (item.getItemId()) {
                 case R.id.confirm_clear_all_tasks:
                         // clear all planning tasks
                         clearAllPlanningTasks();
                         displayPlanningTasks();
                         return true;
                 case R.id.cancel_clear_all_tasks:
                         // cancel pressed, so do nothing
                         return true;
                 case R.id.faq:
                	 	// call faq activity
	                	Intent intent = new Intent(this, FAQActivity.class);
	                    startActivity(intent);
                	 	
                	 	return true;
                 default:
                         return super.onOptionsItemSelected(item);
                 }
         }
         
        // clears all planning tasks in the database
        private void clearAllPlanningTasks() {
                dataSource.open();
                dataSource.deleteAllTasks(DbHelper.TABLE_PLANNINGTASKS);
                dataSource.close();
        }
        
        // switches between planning and schedule activities
        public void switchTabInActivity(int indexTabToSwitchTo){
        	TabWidget ParentActivity;
        	ParentActivity = (TabWidget) this.getParent();
        	ParentActivity.switchTab(indexTabToSwitchTo);
    	}


        @Override
        /**
         * This method generates a Menu from a menu resource file
         */
	    public boolean onCreateOptionsMenu(Menu menu)
	    {
	        //creates a menu inflater
	        MenuInflater inflater = getMenuInflater();
	        
	        //R.menu.main_menu represents the ID of the XML resource file
	        inflater.inflate(R.menu.planning_screen_menu, menu);
	        return true;
	    }
        
        
        @Override
        // This method handles the information received from EnterTaskInfo activity
        // on returning from EnterTaskInfo Activity
        protected void onActivityResult(int requestCode, int resultCode, Intent data){
                super.onActivityResult(requestCode, resultCode, data);
                if(resultCode == Utility.RETURN_CODE_NEW_TASK_INFO) {
                        // got user input for new task
                        Bundle bundle = data.getExtras();
                        
                        // get information form bundle
                        String title = bundle.getString(Utility.BUNDLE_TASK_TITLE);
                        String startTime = bundle.getString(Utility.BUNDLE_TASK_START_TIME);
                        int duration = bundle.getInt(Utility.BUNDLE_TASK_DURATION);
                        int travelTime = bundle.getInt(Utility.BUNDLE_TASK_TRAVEL_TIME);
                        int priority = bundle.getInt(Utility.BUNDLE_TASK_PRIORITY);
                        
                        // write information to database and refresh display
                        dataSource.open();
                        Task newTask = dataSource.createPlanningTask(title, startTime, duration, travelTime, priority, 0);
                        dataSource.close();
                        
                        // check for time conflict with tasks already in the planning list
                        Log.d("planningListSize", planningList.getAllTasks().size() + "-");
                        if(planningList.hasConflict(newTask)){
                        	Log.d(TAG, "New Task Conflict detected");
                        	dataSource.open();
                        	dataSource.deletePlanningTask(newTask.getID());
                        	dataSource.close();
                        	displayConflictDialog(newTask, NEW_TASK_CONFLICT);
                        	
                        } else {
                        	planningList.addTask(newTask);
                            displayPlanningTasks();
                        }
                        
                
                                
                } else if (resultCode == Utility.RETURN_CODE_EDIT_TASK_INFO) {
                        // got edited input for task 
                	
                        Bundle bundle = data.getExtras();
                        
                        // get information from bundle, edit information in database and refresh display
                        Long taskId = bundle.getLong(Utility.BUNDLE_TASK_ID);
                        String title = bundle.getString(Utility.BUNDLE_TASK_TITLE);
                        String startTime = bundle.getString(Utility.BUNDLE_TASK_START_TIME);
                        int duration = bundle.getInt((Utility.BUNDLE_TASK_DURATION));
                        int travelTime = bundle.getInt(Utility.BUNDLE_TASK_TRAVEL_TIME);
                        int priority = bundle.getInt(Utility.BUNDLE_TASK_PRIORITY);
                        
                        // create a task to check for conflicts
                        Time time = new Time();
                        if(startTime == null){
                        	time = null;
                    	} else {
                        	String[] hourMin = startTime.split(":");
                        	time.set(0, Integer.parseInt(hourMin[1]), Integer.parseInt(hourMin[0]), 0, 0, 0);
                    	}
                        
                        Task editTask = new Task(taskId, title, time, duration,
                        		travelTime, priority, false);
                        
                        // check for conflicts
                        Log.d("planningListSize", planningList.getAllTasks().size() + "-");
                        for(Task t : planningList.getAllTasks()) {
                        	Log.d("startTimePlanning", parseTime(t.getStartTime()));
                        }
                        for(Task t : planningList.getAllTasks()) {
                        	Log.d("startTimePlanning", parseTime(t.getStartTime()));
                        }
                        // check for conflicts
                        if(!planningList.hasConflict(editTask)){
                        	 dataSource.open();
                             dataSource.editPlanningTask(taskId, title, startTime, duration, travelTime, priority, 0);
                             dataSource.close();
                             displayPlanningTasks();
                             
                        } else {
                        	// display alert dialog
                        	displayConflictDialog(editTask, EDIT_TASK_CONFLICT);
                        }
                                     
                                               
                }
                else if (resultCode == Utility.RETURN_CODE_START_END_TIME_INFO) {
                	
                	// start and end time for schedule returned
                	Bundle bundle = data.getExtras();
                	String startTimeString = bundle.getString(Utility.BUNDLE_TASK_START_TIME);
                	String endTimeString = bundle.getString(Utility.BUNDLE_TASK_END_TIME);
                	
                	String[] startTimeValues = startTimeString.split(":");
                	String[] endTimeValues = endTimeString.split(":");
                	
                	// time objects created for start and end time
                	Time startTime = new Time();
        			startTime.set(0, Integer.parseInt(startTimeValues[1]), Integer.parseInt(startTimeValues[0]), 0, 0, 0);
        			
                    //List<Task> scheduleList = new ArrayList<Task>();

        			Time endTime = new Time();
        			endTime.set(0, Integer.parseInt(endTimeValues[1]), Integer.parseInt(endTimeValues[0]), 0, 0, 0);
	
        			try {
        				// get the schedule and get the collection of tasks from the schedule
        				Schedule s = ScheduleMaker.generateSchedule(tasksToDisplay, startTime, endTime);
        				
            			scheduleList = s.getTasks();
            			dataSource.open();
            			dataSource.deleteAllTasks(DbHelper.TABLE_PREVIEW);
            			dataSource.savePreviewTasks(scheduleList);
            			dataSource.close();
            			if(scheduleList.size() == tasksToDisplay.size()) {
            				Utility.setAllTasksIncludedFlag(true);
            			}
            			else {
            				Utility.setAllTasksIncludedFlag(false);
            			}
            			Intent newIntent = new Intent(PlanningScreenActivity.this, PreviewScheduleScreenActivity.class);
                        startActivityForResult(newIntent, requestCode);
        			}
        			catch(Exception e) {
        				AlertDialog.Builder builder = new AlertDialog.Builder(this);
        				//builder.setIcon(R.drawable.dialog_question);
        				builder.setTitle("Schedule Calculation Error");
        				builder.setMessage("Unexpected error occured. Please try again.");
        				builder.setInverseBackgroundForced(true);
        				builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
							
							public void onClick(DialogInterface dialog, int which) {
								dialog.dismiss();
							}
						});
        				AlertDialog alert = builder.create();
        				alert.show();
        			}
                }
                else if (resultCode == Utility.RETURN_CODE_SAVE_PREVIEW) {
                	dataSource.open();
                	dataSource.deleteAllTasks(DbHelper.TABLE_REGENERATE);
                	dataSource.saveRegenerateTasks(regenerateTasks);
        			dataSource.deleteAllTasks(DbHelper.TABLE_SCHEDULE);
                	dataSource.saveScheduleTasks(scheduleList);
                	dataSource.close();
                	switchTabInActivity(0);
                }
                else {
                }
        }

		
		 // displays an alert dialog to user indicating a time conflict exists
		private void displayConflictDialog(Task task, String conflictType) {
			Log.d(TAG, "In displayConcliftDialog");
			AlertDialog.Builder builder = new AlertDialog.Builder(this);
			builder.setTitle("Time Conflict");
			
			// build message depending on conflict type
			if(conflictType.equals(NEW_TASK_CONFLICT)){
				builder.setMessage("Task " + task.getTitle() + " not saved. Time conflicting with existing tasks. " +
						"Please try changing start time.");
			} else {
				builder.setMessage("Task " + task.getTitle() + " not edited. " +
						"Time conflicting with existing tasks. Please try changing start time.");
			}
			
			builder.setInverseBackgroundForced(true);
			builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
				
				public void onClick(DialogInterface dialog, int which) {
					
					dialog.dismiss();
				}
			});
			AlertDialog alert = builder.create();
			alert.show();
					
		}
		
		// displays an alert dialog to user to confirm task deletion
		private void displayAlertDialog() {
			AlertDialog.Builder builder = new AlertDialog.Builder(this);
			builder.setTitle("Confirmation");
					
			builder.setMessage("Confirm Task Deletion");
			builder.setInverseBackgroundForced(true);
			builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
				
				public void onClick(DialogInterface dialog, int which) {
									
					dialog.dismiss();
				}
			});
			
			builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
						
				public void onClick(DialogInterface dialog, int which) {
						
					// get the id of task in at the selected row position
	                long taskId = rowPositionToTaskId(selectedRowPosition);
	                                  
	                // delete the task with the given taskId
	                deletePlanningTask(taskId);
	                dialog.dismiss();
	                displayPlanningTasks();
				}
			});
			AlertDialog alert = builder.create();
			alert.show();						
		}
}
